package com.base.monitor.module.biz.message.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.base.monitor.framework.exception.CustomerException;
import com.base.monitor.framework.util.CustomerUtils;
import com.base.monitor.model.constant.CollectConstant;
import com.base.monitor.model.enums.biz.BrightSkyFireControlMainEngineCodeEnum;
import com.base.monitor.model.enums.biz.CollectTypeEnum;
import com.base.monitor.model.enums.code.impl.common.ParamCode;
import com.base.monitor.model.enums.code.impl.common.ResultCode;
import com.base.monitor.model.model.biz.cfg.entity.Gateway;
import com.base.monitor.model.model.biz.cfg.vo.IndicatorCommandVo;
import com.base.monitor.model.model.biz.collect.entity.CollectData;
import com.base.monitor.module.biz.context.CfgContext;
import com.base.monitor.module.biz.context.ClientContext;
import com.base.monitor.module.biz.handler.HandleCollectDataHandler;
import com.base.monitor.module.biz.handler.PushFireControlUpdateTimeHandler;
import com.base.monitor.module.biz.message.Message;
import com.base.monitor.module.biz.util.ChannelUtils;
import com.base.monitor.module.biz.util.ConvertUtils;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 蓝天消防主机的复位消息
 */
@Component
@Slf4j
public class BrightSkyFireControlResetMessage implements Message {

    @Autowired
    private HandleCollectDataHandler handleCollectDataHandler;

    /**
     * 消息类型
     *
     * @return
     */
    @Override
    public String messageType() {
        return CollectConstant.MESSAGE_TYPE_IS_BRIGHT_SKY_FIRE_CONTROL_RESET;
    }

    /**
     * 处理消息
     *
     * @param ctx     netty客户端通道信息
     * @param message 消息内容
     */
    @Override
    public void handle(ChannelHandlerContext ctx, String message) {
//        message = "F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5F5";
        log.info("[蓝天消防]处理ip为{}的消防主机复位消息，消息内容为{}", ctx.channel().remoteAddress(), message);

        // 1.查找是否已经连接过，没有连接过要先注册
        connectedIfAbsent(ctx);

        // 2.更新网关和指标的在线状态
        Gateway gateway = updateOnlineTime(ctx);

        // 3.推送给远端
        pushCollect(gateway.getGatewayId());
    }

    /**
     * 如果该信道不存在的话就要注册信道
     * @param ctx 信道上下文
     */
    private void connectedIfAbsent(ChannelHandlerContext ctx) {
        // 1.获取ip地址
        String ip = ChannelUtils.formatChannelIp(ctx.channel().remoteAddress().toString());

        ClientContext.ChannelInfo channelInfo = ClientContext.getChannelInfoByIp(ip);
        if (channelInfo == null) {
            // 2.生成连接命令。因为消防主机是没有连接命令的
            String connect = manualGenerateConnectMessage();

            // 3.注册信道
            ClientContext.addClient(connect, ctx);
        }
    }

    /**
     * 更新网关和指标的在线时间
     * @param ctx 信道上下文
     * @return 对应的网关信息
     */
    private Gateway updateOnlineTime(ChannelHandlerContext ctx) {
        // 1.更新网关在线时间
        Gateway gateway = getGatewayByIp(ChannelUtils.formatChannelIp(ctx.channel().remoteAddress().toString()));
        CfgContext.addGatewayOnlineTime(gateway.getGatewayId());

        // 2.更新指标在线时间
        List<IndicatorCommandVo> indicators = gateway.getIndicators();
        if (CollectionUtil.isEmpty(indicators)) {
            return gateway;
        }
        List<String> ids = indicators.stream().map(IndicatorCommandVo::getId).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(indicators)) {
            return gateway;
        }
        for (String id : ids) {
            CfgContext.addIndicatorOnlineTime(id);
        }
        return gateway;
    }

    /**
     * 推送给远端
     * @param gatewayId 网关id
     */
    private void pushCollect(Long gatewayId) {
        List<String> list = new ArrayList<>();
        list.add(gatewayId + "");
        list.add("RESET");
        CollectData collect = new CollectData("", CollectTypeEnum.FIRE, list);
        log.info("[蓝天消防]该消防消息:{}为复位消息，需要推送到远端", collect);
        handleCollectDataHandler.addTask(collect);
    }


    /**
     * 手动生成连接命令
     * @return
     */
    private String manualGenerateConnectMessage() {
        String message = generateConnectMessage();
        if (ClientContext.getClientMap().containsKey(message)) {
            message = manualGenerateConnectMessage();
        }
        return message;
    }

    /**
     * 生成随机的连接命令
     * @return
     */
    private String generateConnectMessage() {
        return "[蓝天消防]" + CustomerUtils.getRandomString(5);
    }

    /**
     * 根据ip获取指标id
     * @param ip 信道ip地址
     * @return
     */
    private Gateway getGatewayByIp(String ip) {
        List<Gateway> gatewayVoList = CfgContext.getGatewayVoList();
        if (CollectionUtil.isEmpty(gatewayVoList)) {
            throw new CustomerException(ResultCode.RETURN_DATA_NOT_FOUND, "没有找到这条消息对应的指标");
        }
        List<Gateway> collect = gatewayVoList.stream().filter(item -> item.getGatewayIp().equals(ip)).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(collect)) {
            throw new CustomerException(ResultCode.RETURN_DATA_NOT_FOUND, "没有找到这条消息对应的指标");
        }
        return collect.get(0);
    }
}
